=x= 🌵 Sign In page 後台登入密碼驗證。
📌 使用者於登入頁面輸入帳號及密碼送出後,後端會依取得帳號連進資料庫比對,如果帳號不存在,就送出帳號不存在的說明,如果帳號存在,就取出該帳號 "密碼加鹽加密結果" + "鹽的內容",再將取出的 "鹽的內容" 與登入頁輸入的密碼又一次進行 hash 雜湊加密,最後將加密後的結果比對資料庫取出的 "密碼加鹽加密結果",如果比對不相同,就送出密碼錯誤的說明,如果比對相同就進行跳轉頁面,登入成功。
🧠 密碼如果驗證成功會一併發出 FormsAuthenticationTicket 驗證票,驗證票可用來進行權限的識別導引,以及再後台操作時保持登入狀態,以下程式碼會一併呈現使用方式。
👀 驗證與授權必讀好文1 : 簡介 ASP.NET 表單驗證 (FormsAuthentication) 的運作方式
👀 驗證與授權必讀好文2 : [ASP.NET] Forms 驗證與授權
<configuration>
<system.web>
<authentication mode="Forms"></authentication>
</system.web>
</configuration>
// Argon2 驗證加密密碼
// Hash 處理加鹽的密碼功能
private byte[] HashPassword(string password, byte[] salt)
{
var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));
//底下這些數字會影響運算時間,而且驗證時要用一樣的值
argon2.Salt = salt;
argon2.DegreeOfParallelism = 8; // 4 核心就設成 8
argon2.Iterations = 4; //迭代運算次數
argon2.MemorySize = 1024 * 1024; // 1 GB
return argon2.GetBytes(16);
}
//驗證
private bool VerifyHash(string password, byte[] salt, byte[] hash)
{
var newHash = HashPassword(password, salt);
return hash.SequenceEqual(newHash); // LINEQ
}
//設定驗證票
private void SetAuthenTicket(string userData, string userId)
{
//宣告一個驗證票 //需額外引入 using System.Web.Security;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userId, DateTime.Now, DateTime.Now.AddHours(3), false, userData);
//加密驗證票
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
//建立 Cookie
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
//將 Cookie 寫入回應
Response.Cookies.Add(authenticationCookie);
}
AddHours
要配合使用情境設定,使用者切換頁面時可以保持登入狀態。protected void Button1_Click(object sender, EventArgs e)
{
string password = TextBox2.Text;
// 1.連線資料庫
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
// 2.sql語法 (@參數化避免隱碼攻擊)
string sql = "SELECT * FROM managerData WHERE account = @account";
// 3.創建 command 物件
SqlCommand command = new SqlCommand(sql, connection);
// 4.放入參數化資料
command.Parameters.AddWithValue("@account", TextBox1.Text);
// 5.資料庫用 Adapter 執行指令
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
// 6.建立一個空的 Table
DataTable dataTable = new DataTable();
// 7.將資料放入 Table
dataAdapter.Fill(dataTable);
// 登入流程管理 (Cookie)
if (dataTable.Rows.Count > 0) {
// SQL 有找到資料時執行
//將字串轉回 byte
byte[] hash = Convert.FromBase64String(dataTable.Rows[0]["password"].ToString());
byte[] salt = Convert.FromBase64String(dataTable.Rows[0]["salt"].ToString());
//驗證密碼
bool success = VerifyHash(password, salt, hash);
if (success) {
//宣告驗證票要夾帶的資料 (用;區隔)
string userData = dataTable.Rows[0]["maxPower"].ToString() + ";" + dataTable.Rows[0]["account"].ToString() + ";" + dataTable.Rows[0]["name"].ToString() + ";" + dataTable.Rows[0]["email"].ToString();
//設定驗證票(夾帶資料,cookie 命名) // 需額外引入using System.Web.Configuration;
SetAuthenTicket(userData, TextBox1.Text);
//導頁至權限分流頁
Response.Redirect("CheckAccount.ashx");
}
else {
//資料庫裡找不到相同資料時,表示密碼有誤!
Label4.Text = "password error, login failed!";
Label4.Visible = true;
connection.Close();
return;
}
}
else {
//資料庫裡找不到相同資料時,表示帳號有誤!
Label4.Text = "Account error, login failed!";
Label4.Visible = true;
//終止程式
//Response.End(); //會清空頁面
return;
}
connection.Close();
}
📢 因為使用 Argon2 驗證會增加運算時間,跳轉頁面會有延遲,建議在 .aspx 頁面用 JavaScript 監聽按鈕加入驗證中的 CSS 蓋版動畫,另外登入頁可增加一按鈕當成返回前台首頁的功能,權限分流頁使用 .ashx (泛型處理常式)製作,在後續頁面會一併介紹相關設定及功能。
🧂 要使密碼更安全的作法,其實還要加"安全鹽"或稱作"胡椒",因為鹽會和加密後的密碼一起放在資料庫,如果資料庫被攻擊就可能會被破解,"胡椒"需要另外存放來達到提升安全性的效果,或是把它寫在程式裡,這樣至少也是放在不同地方。
👀 胡椒的使用方式 : How to apply a pepper correctly to bcrypt?
👀 胡椒的維基百科 : Pepper (cryptography)